package cn.iocoder.yudao.server.code;

import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.lfd.dal.dataobject.appraise.AppraiseDO;
import cn.iocoder.yudao.module.lfd.dal.dataobject.customer.CustomerDO;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;


public class EntitytoTableTools {

    public static final String templatePath = "/yudao-server/src/main/resources/DefaultBaseDaoTemplate.ftl";
    public static final String tableName = "lfd_customer";
    public static final Class<?> cls = CustomerDO.class;

    public static void main(String[] args) {
        final Map<String, Object> rootMap = new HashMap<String, Object>();
        rootMap.put("parameterType", cls.getName());
        rootMap.put("tableName", tableName);
        rootMap.put("columns", loadColumns());
        rootMap.put("varcharLength", 200);

        //利用freemark 解析
        @SuppressWarnings("deprecation") final Configuration configuration = new Configuration();
        final StringWriter writer = new StringWriter();
        try {
            String canonicalPath = new File("").getCanonicalPath();
            final Template temp = new Template("生成sql", new FileReader(canonicalPath + templatePath), configuration);
            temp.process(rootMap, writer);
        } catch (IOException e) {
            throw new RuntimeException("取得freemarker模板出错", e);
        } catch (TemplateException e) {
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
            }
        }
        System.out.println(writer.toString().replaceAll("\\\\", ""));
    }


    private static List<Column> loadColumns() {
        final List<Column> columns = new ArrayList<Column>();

        final List<Field> fields = Tools.getWanFields(cls);
        for (Field field : fields) {
            final Column column = new Column();
            column.setJdbcType(Tools.getJdbcType(field.getType()));
            final Class<?> type = field.getType();
            if (BaseDO.class.isAssignableFrom(type)) {
                column.setAlias(field.getName() + ".id");
                column.setName(field.getName() + "Id");
                column.setValue(field.getName() + "." + "id");
                column.setCondition(field.getName() + "!=null and " + field.getName() + ".id!=null");
                column.setIndex(10);
            } else {
                column.setName( field.getName());
                column.setValue(field.getName());
                column.setCondition(field.getName() + "!=null");
                column.setAlias(field.getName());
                column.setIndex(1);
            }
            columns.add(column);
        }
        Collections.sort(columns, Comparator.comparingInt(Column::getIndex));
        return columns;
    }

    private static class Tools {
        public static List<Field> getWanFields(Class<?> cls) {
            final List<Field> fields = new ArrayList<Field>();
            getWantFields(cls, fields);
            return fields;
        }

        private static void getWantFields(Class<?> cls, List<Field> fields) {
            if (!BaseDO.class.isAssignableFrom(cls)) {
                return;
            }
            getWantFields(cls.getSuperclass(), fields);
            final Field[] fs = cls.getDeclaredFields();
            for (Field field : fs) {
                if (!check(field)) {
                    continue;
                }
                fields.add(field);
            }


        }

        private static boolean check(Field field) {
            final int modifier = field.getModifiers();
            if (Modifier.isInterface(modifier)) {
                return false;
            }
            if (Modifier.isStatic(modifier)) {
                return false;
            }
            if (Array.class.isAssignableFrom(field.getType())) {
                return false;
            }
            if (Collection.class.isAssignableFrom(field.getType())) {
                return false;
            }
            if (Map.class.isAssignableFrom(field.getType())) {
                return false;
            }
            return true;
        }

        private static String getJdbcType(Class<?> type) {
            String jdbcType = "VARCHAR";
            if (type == Date.class) {
                jdbcType = "datetime";
            }
            if (type == LocalDateTime.class) {
                jdbcType = "datetime";
            }
            if (type == LocalTime.class) {
                jdbcType = "time";
            }
            if (type == LocalDate.class) {
                jdbcType = "date";
            }
            if (Number.class.isAssignableFrom(type)) {
                if (Long.class.isAssignableFrom(type)){
                    jdbcType = "bigint";
                }else if (Integer.class.isAssignableFrom(type)){
                    jdbcType = "int";
                }
            }
            return jdbcType;
        }

    }

    public static class Column {
        private int index;
        private String condition;
        private String name;
        private String value;
        private String alias;
        private String jdbcType;

        public String getCondition() {
            return condition;
        }

        public void setCondition(String condition) {
            this.condition = condition;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getAlias() {
            return alias;
        }

        public void setAlias(String alias) {
            this.alias = alias;
        }

        public String getJdbcType() {
            return jdbcType;
        }

        public void setJdbcType(String jdbcType) {
            this.jdbcType = jdbcType;
        }

        public int getIndex() {
            return index;
        }

        public void setIndex(int index) {
            this.index = index;
        }
    }


}
